﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace UGCommon
{
  
    class individual
    {
        public List<double> x { get; set; }
        public double f { get; set; }
        public individual i_best { get; set; }


        
    }
    public class PRPC
    {
        private route_list pipe { get; set; }
        private components cmps { get; set; }
        private List<double[]> path { get; set; }
        public int minbendcount { get; set; }
        public int num_p { get; set; }
        public double epoch { get; private set; }
        public double c1 { get; set; }
        public double c2 { get; set; }
        public double c3 { get; set; }
        public double minstraightlength { get; set; }//最小直线段长度

        private individual g_best = new individual();
        private List<individual> individuals = new List<individual>();
        private Random random = new Random();

        JudgeResult js = new JudgeResult();

        old_gridmap odg = new old_gridmap();
        public List<double> maxi = new List<double>();
        public List<double> mini = new List<double>();

        public PRPC(route_list pipe1, components cmps1, List<double[]> path1,
            int minbendcount1, double minstraightlength, int num_p1)
        {
            pipe = pipe1;
            cmps = cmps1;
            path = path1;
            c1 = 0.05;
            c2 = 0.8;
            c3 = 0.1;
            minbendcount = minbendcount1;
            this.minstraightlength = minstraightlength;//最短直线段长度
            num_p = num_p1;
            maxi = Enumerable.Repeat(1.0, 2 * minbendcount).ToList();
            mini = Enumerable.Repeat(0.0, 2 * minbendcount).ToList();
        }
        public void initialize()
        {
            for (int i = 0; i < num_p; i++)
            {
                individual p = new individual();
                List<double> x = new List<double>();

                for (int j = 0; j < minbendcount; j++)
                {
                    x.Add(1 * random.NextDouble());
                    x.Add(1 * random.NextDouble());
                }
                p.x = x;
                p = evaluation_f(p);
                individual p1 = new individual();
                p1 = p;
                p.i_best = p1;
                individuals.Add(p);
            }
            //Random random = new Random(); // Ensure you use the same seed or a different instance for each individual if necessary.

            //for (int i = 0; i < num_p; i++)
            //{
            //    individual p = new individual();
            //    List<double> x = new List<double>();

            //    // Calculate the step size for the values to be added, ensuring they are evenly distributed.
            //    double stepSize = 1.0 / (minbendcount * 2); // Since we're adding two values per index.

            //    for (int j = 0; j < minbendcount; j++)
            //    {
            //        // Start from the minimum possible value and increment by stepSize.
            //        double val1 = j * 2 * stepSize + random.NextDouble() * stepSize;
            //        double val2 = (j * 2 + 1) * stepSize + random.NextDouble() * stepSize;

            //        x.Add(val1);
            //        x.Add(val2);
            //    }

            //    p.x = x;
            //    p = evaluation_f(p); // Assuming this is the correct method name.
            //    individual p1 = new individual();
            //    p1 = p;
            //    p.i_best = p1;
            //    individuals.Add(p);
            //}
            individuals.Sort((indiv1, indiv2) => indiv1.f.CompareTo(indiv2.f));
            // 实现最佳保存选择
            // 保留种群中最好的个体
            g_best = individuals.First();  // 假设最好的个体在列表前面
        }
        private individual evaluation_f(individual p)
        {
            double f = 0;
            List<pipeS> ps = new List<pipeS>();
            List<double[]> allcoorpoints = new List<double[]>();
            allcoorpoints = decode(p);
            //UGTools.writeInListWindow(allcoorpoints.Count.ToString());
            for ( int i=0;i< allcoorpoints.Count - 1;i++)
            {
                //UGTools.writeInListWindow(i.ToString());
                pipeS pp = new pipeS();
                pp.d = pipe.pipediameter;
                double[] allcoorpoint1 = allcoorpoints[i];
                double[] allcoorpoint2 = allcoorpoints[i+1];
                //UGTools.writeInListWindow(allcoorpoint2[0].ToString());
                //UGTools.writeInListWindow(allcoorpoint2[1].ToString());
                //UGTools.writeInListWindow(allcoorpoint2[2].ToString());
                // 使用当前索引的坐标作为p1
                pp.p1 = new double[] { allcoorpoint1[0], allcoorpoint1[1], allcoorpoint1[2] };

                // 使用下一个索引的坐标作为p2
                pp.p2 = new double[] { allcoorpoint2[0], allcoorpoint2[1], allcoorpoint2[2] };

                ps.Add(pp);
            }     
           int  res = js.Judge2(ps, cmps);
            f += 1000 * res;
            f += fitness5(allcoorpoints, minstraightlength);
            p.f = f;
            return p;
        }
        private double fitness5(List<double[]> allpoints, double minStraightPipeLength)
        {
            double f5 = 0;
            double p5 = 0;
            double p6 = 0;
            List<double> p = new List<double>();
            double tolength = 0;
            double reward = 0;
            int numberOfSegments = 0;
            double sumOfSquaredDifferences = 0;
            double sopd = 0;
            // 第一步：计算总长度和有效管段的数量
            for (int i = 0; i < allpoints.Count - 1; i++)
            {
                if (allpoints[i + 1][0] == allpoints[i][0] && allpoints[i + 1][1] == allpoints[i][1] && allpoints[i + 1][2] == allpoints[i][2])
                {
                    continue;
                }

                double[] p1 = convertCoordToPolar(allpoints[i][0], allpoints[i][1], allpoints[i][2]);
                double[] p2 = convertCoordToPolar(allpoints[i+1][0], allpoints[i + 1][1], allpoints[i + 1][2]);
                double[] v = new double[] {p2[0]-p1[0], p2[1] - p1[1] , p2[2] - p1[2] };
                if (i != 0 && i != allpoints.Count - 1)
                {
                    p6 += p1[0];
                    p.Add(p1[0]);
                }

                p5 += p1[0];
                if ( i == allpoints.Count - 1)
                {
                    p5 += p2[0];
                    p6 += p2[0];
                    p.Add(p2[0]);
                }
                double pipelength = UGMath.TwoPointDistance(allpoints[i + 1], allpoints[i]);
                tolength += pipelength;
                numberOfSegments++;

                if ((v[0]<=5e-3&& v[1] >0) || (v[0] > 0 && v[1] <= 5e-3))
                {
                    reward += 25;
                }

                if (pipelength < minStraightPipeLength * 1.1 || pipelength > minStraightPipeLength * 2.4)
                {
                    f5 += Math.Max(minStraightPipeLength * 1.1 - pipelength, pipelength - minStraightPipeLength * 2.4);
                }
            }

            // 第二步：计算平均长度
            double averageLength = tolength / numberOfSegments;
            double averagep = p5 / numberOfSegments;
            double averagep6 = p6 / numberOfSegments;
            // 第三步：计算与平均长度之差的平方和
            for (int i = 0; i < allpoints.Count - 1; i++)
            {
                if (allpoints[i + 1][0] == allpoints[i][0] && allpoints[i + 1][1] == allpoints[i][1] && allpoints[i + 1][2] == allpoints[i][2])
                {
                    continue;
                }
                double pipelength = UGMath.TwoPointDistance(allpoints[i + 1], allpoints[i]);
                sumOfSquaredDifferences += Math.Pow(pipelength - averageLength, 2);
            }
            foreach (var i in p)
            {
               sopd += Math.Pow(i - averagep6, 2);
            }


            // 第四步：计算标准差
            double standardDeviation = Math.Sqrt(sumOfSquaredDifferences / numberOfSegments);
            double sdp = Math.Sqrt(sopd / numberOfSegments);

            return 1.5 * Math.Ceiling(Math.Ceiling(f5*f5 / 20)) + 0.25*tolength+ 0.5*standardDeviation + 0.05*sdp + 0.75*averagep-0.5*reward;
        }
        public void update()
        {
           
            // 实现最佳保存选择
            // 保留种群中最好的个体
            individual bestIndividual = individuals.First();  // 假设最好的个体在列表前面
            List<individual> newPopulation = new List<individual>();

            // 将最好的个体加入到新的种群中
            newPopulation.Add(bestIndividual);

            // 实现锦标赛选择
            int tournamentSize = 5;  // 设置锦标赛的大小
            int numParents = individuals.Count - 1; ;  // 减去已经保留的最佳个体
            for (int i = 0; i < numParents; i++)
            {
                // 从当前种群中随机选择tournamentSize个个体
                List<individual> tournamentParticipants = new List<individual>();
                while (tournamentParticipants.Count < tournamentSize)
                {
                    int randomIndex = random.Next(0, individuals.Count);
                    if (!tournamentParticipants.Contains(individuals[randomIndex]))
                    {
                        tournamentParticipants.Add(individuals[randomIndex]);
                    }
                }

                // 选择锦标赛中的最佳个体
                individual winner = tournamentParticipants.OrderBy(indiv => indiv.f).First();

                // 更新状态并添加到新的种群中
                newPopulation.Add(winner);
            }

            // 更新种群
            individuals = newPopulation;
            // 交叉操作
            List<individual> offspringPopulation = new List<individual>();
            for (int i = 0; i < newPopulation.Count / 2; i++)
            {
                individual parent1 = newPopulation[i];
                individual parent2 = newPopulation[newPopulation.Count - 1 - i];

                if (random.NextDouble() < c2)
                {
                    individual child1 = crossover(parent1, parent2);
                    individual child2 = crossover(parent2, parent1);

                    // 变异操作
                    if (random.NextDouble() < c3)
                    {
                        child1 = mutate(child1);
                        child2 = mutate(child2);
                    }

                    offspringPopulation.Add(child1);
                    offspringPopulation.Add(child2);
                }
                else
                {
                    // 变异操作
                    if (random.NextDouble() < c3)
                    {
                        parent1 = mutate(parent1);
                        parent2 = mutate(parent2);
                    }
                    offspringPopulation.Add(parent1);
                    offspringPopulation.Add(parent2);
                }
            }

            // 更新种群
            individuals = offspringPopulation;
            for (int i = 0; i < num_p; i++)
            {
                individuals[i] = evaluation_f(individuals[i]);
                //UGTools.writeInListWindow("11+"+individuals[i].f.ToString());
                //UGTools.writeInListWindow("11+" + individuals[i].i_best.f.ToString());
                //if (individuals[i].f< individuals[i].i_best.f)
                //{
                //    individuals[i].i_best = individuals[i];
                //}
            }
            individuals.Sort((indiv1, indiv2) => indiv1.f.CompareTo(indiv2.f));
            bestIndividual = individuals.First();  // 假设最好的个体在列表前面
            if (g_best.f >= bestIndividual.f)
            {
                g_best = bestIndividual;
            }
        }
        // 交叉操作示例
        private individual crossover(individual p, individual g)
        {
            List<double> tempm = p.x;
            List<double> tempf = g.x;
            List<double> childX = new List<double>();

            int min = Math.Min(tempf.Count, tempm.Count);
            int max = Math.Min(tempf.Count, tempf.Count);

            int locat = random.Next(min);
            List<double> long_temp = tempf.Count >= tempm.Count ? tempf : tempm;
            double w = 0.8;
            for (int m = 0; m < min; m++)
            {
                if (random.NextDouble() <= 0.5)
                {
                    childX.Add(w*tempm[m]+ (1-w)*tempf[m]);
                }
                else
                {
                    childX.Add(w * tempf[m]+ (1 - w) * tempm[m]);
                }
            }
            for (int m = 0; m < (long_temp.Count - min) / 3; m++)
            {
                if (random.NextDouble() <= 0.5)
                {
                    childX.Add(long_temp[min + 3 * m]);
                    childX.Add(long_temp[min + 3 * m + 1]);
                    childX.Add(long_temp[min + 3 * m + 2]);
                }
            }
            individual child = new individual();
            child.x = childX;
            return child;
        }

        // 变异操作示例
        private individual mutate(individual individual)
        {
            // 实现具体的变异逻辑
            // 例如，可以以一定的概率改变个体的某个基因
            for (int i = 0; i < individual.x.Count; i++)
            {
                if (random.NextDouble() < c3)
                {
                    individual.x[i] = random.NextDouble();
                }
                // 以一定概率删除一个点
                if (random.NextDouble() < c1 ) // 确保至少保留两个点
                {
                    int indexToRemove = random.Next(1, individual.x.Count - 1); // 避免删除第一个或最后一个点
                    individual.x.RemoveAt(indexToRemove);
                    individual.x.RemoveAt(indexToRemove-1);
                }

                // 以一定概率添加一个点
                if (random.NextDouble() < c1 && individual.x.Count>2)
                {
                    int indexToAdd = random.Next(1, individual.x.Count); // 在中间位置添加新点
                    double newPoint = random.NextDouble();
                    individual.x.Insert(indexToAdd, newPoint);
                    individual.x.Insert(indexToAdd, newPoint);
                }
            }
            
            return individual;
        }
        // 终止条件检查示例
        private bool terminationConditionMet()
        {
            // 实现具体的终止条件逻辑
            // ...
            return false;  // 返回是否满足终止条件
        }
   

        public List<double[]> run(int cycle_, out double finally_fitness)
        {
            List<double[]> routing = new List<double[]>();
            finally_fitness = 0;

            initialize();

            int diedainum = 0;
            for (; diedainum < cycle_; diedainum++)
            {
                epoch = diedainum / cycle_;
                update();
                UGTools.writeInListWindow(g_best.f.ToString());
                // 终止条件检查
                if (terminationConditionMet())
                {
                    break;
                }

            }
            UGTools.writeInListWindow("done");
            routing = decode(g_best);
            return routing;
        }
        private List<double[]>decode(individual p)
        {
            List<double[]> pipeline =new List<double[]>();
            pipeline.Add(path[1]);
            for (int i=0;i<p.x.Count-1;i+=2)
            {
                double yt = p.x[i];
                double po = p.x[i + 1];
                int index =Convert.ToInt32( Math.Floor(yt*path.Count));
                double[] point = path[index];

                point = convertCoordToPolar(point[0], point[1], point[2]);
                point[0] = po * 0.3*(cmps.casing.d)+ 0.8*(cmps.casing.d);
                point = convertPolarToCoord(point[0], point[1], point[2]);
                //point = odg.grid2coord(point);
                pipeline.Add(point);
            }
            pipeline.Add(path[path.Count-2]);
            return pipeline;
        }
        private double[] convertPolarToCoord(double rho, double theat, double z)
        {
            double[] rt_array = new double[3];
            rt_array[0] = z;
            rt_array[1] = rho * Math.Cos(theat);
            rt_array[2] = rho * Math.Sin(theat);
            return rt_array;
        }
        private double[] convertCoordToPolar(double x, double y, double z)
        {
            double[] rt_array = new double[3];
            rt_array[0] = Math.Sqrt(y * y + z * z);
            rt_array[1] = Math.Atan2(z, y);
            rt_array[2] = x;
            return rt_array;
        }
    }
}
